import { createStore,Commit } from "vuex"
import axios,{AxiosRequestConfig} from "axios"
import { arrToObj, objToArr } from "./helper"

// eslint-disable-next-line @typescript-eslint/ban-types
export interface ResponseType<P = {}>{  //从后端获取过来的数据形式
    code:number;
    msg:string;
    data:P;
}

export interface UserProps{
    isLogin:boolean;
    nickName?:string;
    _id?:string;
    avatar?: ImageProps;
    column?:string;
    email?:string;
    description?: string;
}

export interface ImageProps{
    _id?:string;    //图片id
    url?:string;    //图片路径
    createdAt?:string 
    fitUrl?:string  //保存使用阿里云oss的图片处理后的图片url路径
}
export interface ColumnProps {
    _id: string;    //专栏id
    title: string;  //专栏标题
    avatar?: ImageProps;    //专栏图片
    description: string;    //专栏描述
}
export interface PostProps {    //文章的接口，里面有文章的各种属性
    _id?: string;   //文章的id
    title: string;  //文章标题
    excerpt?:string //文章摘要
    content?: string;   //文章详情页的内容属性
    image?: ImageProps | string;    //文章的图片
    createdAt?: string; //文章的创建时间
    column: string; //专栏id
    author?:UserProps | string   //这篇文章属于哪个用户
    isHTML?: boolean;
}

const getAndCommit = async (url:string,mutationName:string,commit:Commit)=>{
    commit('setLoading',true)
    const {data} = await axios.get(url)
    commit(mutationName,data)
    return data
    // commit('setLoading',false)
}

const postAndCommit = async (url:string,mutationName:string,commit:Commit,payload:any)=>{
    commit('setLoading',true)
    const {data} = await axios.post(url,payload)
    commit(mutationName,data)
    return data
    // commit('setLoading',false)
}
//asyncAndCommit方法用来替代post,get请求,默认为get请求
const asyncAndCommit = async (url:string,mutationName:string,commit:Commit,config:AxiosRequestConfig = { method:'get' },extraData?:any)=>{
    const { data } =await axios(url,config)
    if(extraData){
        commit(mutationName,{data,extraData})
    }else{
        commit(mutationName,data)
    }
    return data
}


export interface GlobalErrorProps{
    status:boolean; //是否有错误
    message?:string;    //错误提示信息
}

interface ListProps<P>{
    [id:string]:P;
}

export interface readPostRecord{
    currentPage?:number
    total?:number
}

export interface GlobalDataProps{   //定义整个系统存放数据的全部的数据类型
    error:GlobalErrorProps;
    token:string;
    loading:boolean;
    columns: { data: ListProps<ColumnProps>; currentPage: number;total:number};
    posts: { data: ListProps<PostProps>; currentPostPage:ListProps<readPostRecord>};
    user:UserProps;
}
const store = createStore<GlobalDataProps>({
    state:{
        error:{status:false},   //错误信息的状态
        token:localStorage.getItem('token') || '',  //token值，保存着返回的数据信息
        loading:false,  //加载的状态
        //用数组data保存所有专栏的数据，currentPage为当前页，total为专栏的总页数
        columns:{data:{},currentPage:0,total:0},
        posts:{data:{},currentPostPage:{}},   //用数组保存所有文章
        user:{isLogin:false}    //存放用户信息
    },
    mutations:{
        // login(state){
        //     state.user = {...state.user,isLogin:true,name:'viking'}
        // },
        //新建文章,这里的newPost是第二次请求后端得来的，不是第一次请求后端的来的
        //(第一次请求在Uploader,第二次在本文件中调用postAndConmmit)
        createPost(state,newPost){
            //const author=newPost.data.author
            state.posts.data[newPost._id]=newPost   //放进state中的posts里
        },
        fetchColumns(state,rawData){    //获取页数和大小的专栏
            const {data} = state.columns
            //count为专栏的总数,list是专栏的信息，获取几个专栏，list中就会有相对应的专栏数量
            const {list,count,currentPage} =rawData.data    
            state.columns = {
                data:{...data,...arrToObj(list)},   //接着上次获取到的数据基础上，添加新的数据,因为分页需要在点击加载更多按钮后，在原有继续上添加更多的专栏
                total:count,    //专栏总数赋值给total
                currentPage:currentPage * 1 //currentPage有可能是字符串，这里类型转换一下
            }
        },
        fetchColumn(state,rawData){     //获取专栏页的详情介绍内容
            state.columns.data[rawData.data.data._id]=rawData.data.data
        },
        updateColumn(state, { data }) {
            state.columns.data[data._id] = data
        },
        fetchPosts(state,{data:rawData,extraData:columnId}){      //获取一个专栏中的所有文章
            const {data} = state.posts
            const {list,count,currentPage} =rawData.data
            state.posts.data = {...data,...arrToObj(list)}//接着上次获取到的数据基础上，添加新的数据
            //每一个专栏都有读文章的记录，记录的是主要内容是读到哪里了，这个专栏的文章总数是多少
            state.posts.currentPostPage[columnId]={currentPage:currentPage*1,total:count}
        },
        updatePost(state,{ data }){ //编辑自己发布的文章
            //在JavaScript中，map()方法可以按照原始数组元素顺序依次处理元素
            //返回一个新数组，数组中的元素为原始数组元素调用函数处理后的值
            //state.posts里面只有一篇文章
            //因为在专栏中点击具体文章，会调用fetchPost方法，将state.posts赋值为点击的文章的数据
            /*state.posts = state.posts.map(post=>{   
                if(post._id === data._id){
                    return data
                }else{
                    return post
                }
            })*/
            state.posts.data[data._id]=data
        },
        updateUser(state, { data }) {
            state.user = { isLogin: true, ...data }
        },
        setLoading(state,status){       //Loading转圈加载
            state.loading = status
        },
        setError(state,e:GlobalErrorProps){ //不用请求后端服务器
            state.error = e
        },
        fetchCurrentUser(state,rawData){    //获取当前登录用户信息，显示在右上角
            state.user = {isLogin:true,...rawData.data}
        },
        login(state,rawData){       //登陆，将登陆的信息token存入localStorage，防止刷新后需要重新登陆
            const {token} = rawData.data
            state.token=token
            localStorage.setItem('token',token) //往localStorage中存入token
            //主动请求一次签发Token的接口并设置到axios的默认headers中，以此达到后续的axios请求都带上Token头
            axios.defaults.headers.common.Authorization = `Bearer ${token}`
        },
        logout(state){
            state.user={isLogin:false}
            state.token=''
            localStorage.removeItem('token')
            delete axios.defaults.headers.common.Authorization
        },
        fetchPost(state,rawData){
            state.posts.data[rawData.data._id]=rawData.data
        },
        deletePost(state,{data}){   //删除文章
            delete state.posts.data[data._id]
        }
    },
    getters:{
        getColumns:(state)=>{
            return objToArr(state.columns.data)
        },
        getColumnById:(state)=>(id:string)=>{   //通过专栏的id找到专栏（一个对象），返回
            //return state.columns.find(c=>c._id===id)
            return state.columns.data[id]
        },
        getPostsByCid:(state)=>(cid:string)=>{  //cid为专栏的id
            //return state.posts.filter(post=>post.column===cid)  //找出专栏为cid的所有文章组成一个数组
            return objToArr(state.posts.data).filter(post=>post.column===cid)
        },
        getCurrentPost:(state)=>(pid:string)=>{   //查找指定文章
            //return state.posts.find(post=>post._id===pid) //优化之前
            return state.posts.data[pid] //优化之后
        },
        getPostRecord:(state)=>(id:string)=>{
            return state.posts.currentPostPage
        }
    },
    actions:{
        fetchColumns({state,commit},params={}){
            const {currentPage = 1,pageSize = 5} = params   //默认值为当前页为第一页，页面有5条数据
            /*if(!state.columns.isLoaded){    //如果没有加载过，需要发请求
                return getAndCommit(`/columns?`,'fetchColumns',commit) 
            }*/
            if(state.columns.currentPage < currentPage){    //该访问currentPage页了，需要发请求
                return asyncAndCommit(`/columns?currentPage=${currentPage}&pageSize=${pageSize}`,'fetchColumns',commit,{method:'get'})     
            }
        },
        fetchColumn({state,commit},cid){
            if(!state.columns.data[cid]){   //如果cid的专栏没被加载过，那就发送请求
                return asyncAndCommit(`/columns/${cid}?`,'fetchColumn',commit,{method:'get'},cid) 
            }
        },
        fetchPosts({state,commit},{params,id}){
            const {currentPage = 1,pageSize = 6} = params   //默认值为当前页为第一页，页面有6条数据
            const record = state.posts.currentPostPage[id]
            if((record && record.currentPage && record.currentPage <= currentPage) || !record){  //state.posts.currentPage是目前已显示到的页数,currentPage是用户想看的下一页
                return asyncAndCommit(`/columns/${id}/posts?currentPage=${currentPage}&pageSize=${pageSize}&`,'fetchPosts',commit,{method:'get'},id) 
            }
        },
        fetchPost({commit},pid){
            const currentPost = this.state.posts.data[pid]
            //没有获取到点击的文章或者是只是文章内容没有获取到(专栏里显示的文章，没有文章的具体内容，只有简单的介绍)
            if(!currentPost || !currentPost.content){   
                return asyncAndCommit(`/posts/${pid}`,'fetchPost',commit,{method:'get'})
            } else {
                return Promise.resolve({data : currentPost})
            }
        },
        updatePost({commit},{id,payload}){
            return asyncAndCommit(`/posts/${id}`,'updatePost',commit,{
                method:'patch',
                data:payload
            })
        },
        updateColumn({ commit }, { id, payload }) {
            return asyncAndCommit(`/columns/${id}`, 'updateColumn', commit, { method: 'patch', data: payload })
        },
        updateUser({ commit }, { id, payload }) {
            return asyncAndCommit(`/user/${id}`, 'updateUser', commit, { method: 'patch', data: payload })
        },
        fetchCurrentUser({commit}){
            return asyncAndCommit('/user/current','fetchCurrentUser',commit,{method:'get'})
        },
        login({commit},payload){
            return asyncAndCommit('/user/login','login',commit,{method:'post', data: payload }) 
        },
        createPost({commit},payload){   //创建文章的时候，总共请求了后端两次，这里一次，Uploader里面一次
            return asyncAndCommit('/posts','createPost',commit,{method:'post', data: payload})
        },
        deletePost({commit},id){
            return asyncAndCommit(`/posts/${id}`,'deletePost',commit,{method:'delete'})
        },
        loginAndFetch({dispatch},loginData){    //登陆后立马获取登录用户信息，并在桌面上显示昵称
            return dispatch('login',loginData).then(()=>{
                return dispatch('fetchCurrentUser')
            })
        }
    }
})

export default store